package jeye.utils;

import static java.awt.RenderingHints.KEY_ANTIALIASING;
import static java.awt.RenderingHints.KEY_INTERPOLATION;
import static java.awt.RenderingHints.KEY_RENDERING;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;
import static java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR;
import static java.awt.RenderingHints.VALUE_RENDER_QUALITY;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;

import jeye.Defaults;

import org.apache.log4j.Logger;

public class ImageUtils {
	
	private static final Logger LOG = Logger.getLogger(ImageUtils.class);
	
	public static InputStream getInputStreamFromImage(BufferedImage image) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		try {
			ImageIO.write(image, Defaults.OUTPUT_FORMAT, baos);
		} catch (IOException e) {
			LOG.error("Error during converting image to IOStream", e);
		}
		
		return new ByteArrayInputStream(baos.toByteArray());
	}
	
	public static byte[] getBytesFromImage(BufferedImage image) {
		return getBytesFromImage(image, Defaults.CAPTURE_QUALITY);
	}
	
	public static byte[] getBytesFromImage(BufferedImage image, float quality) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		try {
			write(image, Defaults.OUTPUT_FORMAT, baos, quality);
		} catch (IOException e) {
			LOG.error("Error during converting image to byte array", e);
		}
		
		return baos.toByteArray();
	}
	
	@SuppressWarnings("unused")
	private static BufferedImage doubleInterlaceImage(BufferedImage image) {
		int height = image.getHeight();
		int width = image.getWidth();
		BufferedImage result = new BufferedImage(width, height / 2, image.getType());
		Graphics2D target = result.createGraphics();
		
		for(int i=0;i<width/2;i++) {
			for(int j=0;j<height/2;j++) {
				int x = i*2;
				int y = j*2;
				target.drawImage(image, i, j, i+1, j+1, x, y, x+1, j+1, null);
			}
		}
		
		return result;
	}
	
	@SuppressWarnings("unused")
	private static BufferedImage interlaceImage(BufferedImage image) {
		int height = image.getHeight();
		int width = image.getWidth();
		BufferedImage result = new BufferedImage(width, height / 2, image.getType());
		Graphics2D target = result.createGraphics();
		int j = 0;
		
		for(int i=0;i<height;i++) {
			if(i%2 == 0) {
				target.drawImage(image, 0, j, width, j+1, 0, i, width, i+1, null);
				j++;
			} 
		}
		
		return result;
	}
	
	private static void write(RenderedImage image, String outputFormat, Object object, float quality) throws IOException {
		ImageWriter writer = ImageIO.getImageWritersByFormatName(Defaults.OUTPUT_FORMAT).next();
		ImageWriteParam param = writer.getDefaultWriteParam();
		ImageOutputStream ios = ImageIO.createImageOutputStream(object);
		
		param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		param.setCompressionQuality(quality);
		
		writer.setOutput(ios);
		
		writer.write(null, new IIOImage(image, null, null), param);
	}
	
	public static void write(RenderedImage image, String outputFormat, OutputStream stream, float quality) throws IOException {
		write(image, outputFormat, (Object)stream, quality);
	}
	
	public static void write(RenderedImage image, String outputFormat, File file, float quality) throws IOException {
		write(image, outputFormat, (Object)file, quality);
	}
	
	private static int getNewSize(int width, int imageWidth, int imageHeight) {
		return imageHeight * width / imageWidth;
	}
	
	public static byte[] resizeImage(byte[] imageBytes, int width, int height) throws IOException {
		return resizeImage(imageBytes, width, height, Defaults.CAPTURE_QUALITY);
	}
	
	public static byte[] resizeImage(byte[] imageBytes, int width, int height, float quality) throws IOException {
		ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
		BufferedImage image = ImageIO.read(bais);
		
		image = resizeImage(image, width, height);
//		image = interlaceImage(image);
		
		return getBytesFromImage(image, quality);
	}
	
	public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
		int imageWidth = image.getWidth();
		int imageHeight = image.getHeight();
		int dW = imageWidth - width;
		int dH = imageHeight - height;
		
		if(dW > dH) {
			height = getNewSize(width, imageWidth, imageHeight); 
		}
		else {
			width = getNewSize(height, imageHeight, imageWidth);
		}
		
		BufferedImage resizedImage = new BufferedImage(width, height, image.getType());
		Graphics2D g = resizedImage.createGraphics();
		
		g.setComposite(AlphaComposite.Src);

		g.setRenderingHint(KEY_INTERPOLATION, VALUE_INTERPOLATION_BILINEAR);
		g.setRenderingHint(KEY_RENDERING, VALUE_RENDER_QUALITY);
		g.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);

		g.drawImage(image, 0, 0, width, height, null);
		g.dispose();
		
		return resizedImage;
	}

}
